<html>
<head><meta charset="utf-8"><title>Determine untupled closure args from Instance? · t-compiler/help · Zulip Chat Archive</title></head>
<h2>Stream: <a href="https://rust-lang.github.io/zulip_archive/stream/182449-t-compiler/help/index.html">t-compiler/help</a></h2>
<h3>Topic: <a href="https://rust-lang.github.io/zulip_archive/stream/182449-t-compiler/help/topic/Determine.20untupled.20closure.20args.20from.20Instance.3F.html">Determine untupled closure args from Instance?</a></h3>

<hr>

<base href="https://rust-lang.zulipchat.com">

<head><link href="https://rust-lang.github.io/zulip_archive/style.css" rel="stylesheet"></head>

<a name="247460249"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/182449-t-compiler/help/topic/Determine%20untupled%20closure%20args%20from%20Instance%3F/near/247460249" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alexa VanHattum <a href="https://rust-lang.github.io/zulip_archive/stream/182449-t-compiler/help/topic/Determine.20untupled.20closure.20args.20from.20Instance.3F.html#247460249">(Jul 28 2021 at 13:42)</a>:</h4>
<p>Is there a way to determine whether a function's last argument is a tuple that needs to be untupled from the <code>rustc_middle::ty::Instance</code> of the function?</p>
<p>For the <a href="https://github.com/model-checking/rmc">Rust Model Checker</a>, we are trying to match Rust's LLVM backend semantics for function calls, which requires untupling/spreading out the last argument to a closure. We previously were doing the check at call-site by whether the function's type kind was a <code>Closure</code>, but this fails in cases where the call is through a vtable, such as this one:</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">p</span><span class="w"> </span>: <span class="kp">&amp;</span><span class="nc">dyn</span><span class="w"> </span><span class="nb">Fn</span><span class="p">(</span><span class="kt">i32</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&amp;|</span><span class="n">y</span><span class="o">|</span><span class="w"> </span><span class="fm">assert!</span><span class="p">(</span><span class="n">y</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">2</span><span class="p">);</span><span class="w"></span>
<span class="w">    </span><span class="n">p</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span><span class="w"></span>
</code></pre></div>
<p>Instead, we are moving to match the LLVM backend (and Cranelift's) decision logic for the call site, which involves checking whether the call's ABI is <code>Abi::RustCall</code>. However, I'm now running into issues where our functions fail to type check because we are again relying on whether the function is a <code>Closure</code> in generating the function signature itself (code is <a href="https://github.com/model-checking/rmc/blob/22d72ef243a695cf3d48f517f61ab0a8a9142dc0/compiler/rustc_codegen_llvm/src/gotoc/metadata.rs#L305">here</a>). If I try to check the ABI against  <code>Abi::RustCall</code> there as well, we run into type issues in how the untupled arguments are used within the function.</p>
<p>Is the correct fix to check the call ABI against <code>Abi::RustCall</code>when generating the function itself (and it's type signature), and then insert logic like <a href="https://github.com/rust-lang/rust/blob/a55748ffe94e71f841c7b1d752779b0db138b342/compiler/rustc_codegen_ssa/src/mir/mod.rs#L280">this</a> from the LLVM backend to re-tuple the args? Or is there another way to determine the correct, untupled function signature from an <code>Instance</code>?</p>
<p>Thanks so much!</p>



<a name="247466176"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/182449-t-compiler/help/topic/Determine%20untupled%20closure%20args%20from%20Instance%3F/near/247466176" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> bjorn3 <a href="https://rust-lang.github.io/zulip_archive/stream/182449-t-compiler/help/topic/Determine.20untupled.20closure.20args.20from.20Instance.3F.html#247466176">(Jul 28 2021 at 14:26)</a>:</h4>
<p>If the abi is "rust-call", you must take all arguments except for the last one verbatim and untuple the last one. When codegening the actual body, you must check if <code>mir.spread_arg == Some(param)</code> where <code>param</code> is the MIR level parameter you are currently codegening and in that case take all the remaining parameters and put it in the <code>param</code> tuple. If <code>mir.spread_arg</code> is <code>None</code>, that means you are a closure and the parameters are already untupled.</p>



<a name="247466206"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/182449-t-compiler/help/topic/Determine%20untupled%20closure%20args%20from%20Instance%3F/near/247466206" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> bjorn3 <a href="https://rust-lang.github.io/zulip_archive/stream/182449-t-compiler/help/topic/Determine.20untupled.20closure.20args.20from.20Instance.3F.html#247466206">(Jul 28 2021 at 14:26)</a>:</h4>
<p><span class="user-mention" data-user-id="418083">@Alexa VanHattum</span></p>



<a name="247471886"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/182449-t-compiler/help/topic/Determine%20untupled%20closure%20args%20from%20Instance%3F/near/247471886" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alexa VanHattum <a href="https://rust-lang.github.io/zulip_archive/stream/182449-t-compiler/help/topic/Determine.20untupled.20closure.20args.20from.20Instance.3F.html#247471886">(Jul 28 2021 at 15:09)</a>:</h4>
<p>Thank you, super helpful to know that approach is necessary! </p>
<p>A more philosophical question: is there a reason why this transformation needs to happen in each backend, instead of at the MIR level itself (or via a shared pass on MIR)? I noticed there's already a <a href="https://github.com/rust-lang/rust/blob/fed59d669c5ca3c0e9c39dcb1f6510b5876ede64/compiler/rustc_codegen_cranelift/src/abi/mod.rs#L186">comment in the Cranelift backend</a> saying the logic is adapted from elsewhere, and it's looking like RMC will have a very similar comment. Is it an intentional design choice to leave the decision to do the transformation on each backend, or is this something that might be moved to MIR in the future?</p>



<a name="247471956"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/182449-t-compiler/help/topic/Determine%20untupled%20closure%20args%20from%20Instance%3F/near/247471956" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> bjorn3 <a href="https://rust-lang.github.io/zulip_archive/stream/182449-t-compiler/help/topic/Determine.20untupled.20closure.20args.20from.20Instance.3F.html#247471956">(Jul 28 2021 at 15:10)</a>:</h4>
<p>It can't be moved into MIR as we don't support variadic generics.</p>



<a name="247472210"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/182449-t-compiler/help/topic/Determine%20untupled%20closure%20args%20from%20Instance%3F/near/247472210" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> bjorn3 <a href="https://rust-lang.github.io/zulip_archive/stream/182449-t-compiler/help/topic/Determine.20untupled.20closure.20args.20from.20Instance.3F.html#247472210">(Jul 28 2021 at 15:11)</a>:</h4>
<p>What would the MIR be for</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">struct</span> <span class="nc">MyClosure</span><span class="p">;</span><span class="w"></span>

<span class="k">impl</span><span class="o">&lt;</span><span class="n">Args</span><span class="o">&gt;</span><span class="w"> </span><span class="nb">FnOnce</span><span class="o">&lt;</span><span class="n">Args</span><span class="o">&gt;</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">MyClosure</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">type</span> <span class="nc">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">();</span><span class="w"></span>

<span class="w">    </span><span class="k">extern</span><span class="w"> </span><span class="s">"rust-call"</span><span class="w"> </span><span class="k">fn</span> <span class="nf">call_once</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">args</span>: <span class="nc">Args</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="p">()</span><span class="w"> </span><span class="p">{}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>if it was lowered at MIR level? <code>MyClosure</code> can be called with any amount of arguments.</p>



<a name="247517166"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/182449-t-compiler/help/topic/Determine%20untupled%20closure%20args%20from%20Instance%3F/near/247517166" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alexa VanHattum <a href="https://rust-lang.github.io/zulip_archive/stream/182449-t-compiler/help/topic/Determine.20untupled.20closure.20args.20from.20Instance.3F.html#247517166">(Jul 28 2021 at 21:03)</a>:</h4>
<p>Ah I see, thanks for the explanation! Much appreciated.</p>



<hr><p>Last updated: Aug 07 2021 at 22:04 UTC</p>
</html>